/***************************************************************************
 *   Copyright (C) 2007 by Warren Kenny   *
 *   warren.kenny@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include <gsContainer/gsString.h>

gsString::gsString() :
m_buffer( GS_NULL ),
m_size( 0 ),
m_capacity( 0 )
{
}

gsString::gsString( const gsChar character ) :
m_size( 1 ),
m_capacity( 1 + GS_STRING_NULL_TERMINATOR_BUFFER_LENGTH )
{
	m_buffer = new gsChar[ m_capacity ];
	m_buffer[0] = character;
}
	
gsString::gsString( const gsChar* string ) :
m_size( 0 ),
m_capacity( 0 )
{
	gsInt size = stringSize( string );
	
	m_capacity = size + GS_STRING_NULL_TERMINATOR_BUFFER_LENGTH;
	
	m_buffer = new gsChar[ m_capacity ];
	m_size = size;
			
	stringCopy( m_buffer, string, size );

}
	
gsString::gsString( const gsString &other )
{
	*this = other;
}
	
gsString::gsString( const gsUInt length, const gsChar* string, const gsUInt index )
{
	gsInt size = stringSize( string );
	
	if( size > length )
	{
		m_size = length;
	}
	else
	{
		m_size = size;
	}
	
	m_capacity = m_size + GS_STRING_NULL_TERMINATOR_BUFFER_LENGTH;
	m_buffer = new gsChar[ m_capacity ];
	
	stringCopy( m_buffer, string, m_size );
}
	
gsString::gsString( const gsUInt length, const gsString& string, const gsUInt index )
{
	gsInt size = string.m_size;
	
	if( size > length )
	{
		m_size = length;
	}
	else
	{
		m_size = size;
	}
	
	m_capacity = m_size + GS_STRING_NULL_TERMINATOR_BUFFER_LENGTH;
	m_buffer = new gsChar[ m_capacity ];
	
	stringCopy( m_buffer, string.m_buffer, m_size );
}
		
gsString& gsString::operator=( const gsString& other )
{
	m_size = other.m_size;
	m_capacity = other.m_capacity;
	
	if( other.m_buffer != GS_NULL )
	{
		if( m_buffer )
		{
			delete[] m_buffer;
			m_buffer = GS_NULL;
		}
		
		m_buffer = new gsChar[ m_capacity ];
		
		stringCopy( m_buffer, other.m_buffer, m_capacity );
	}
	
	return (*this);
}
		
gsBool gsString::operator==( const gsString& other )
{
	return stringCompare( m_buffer, other.m_buffer );
}
	
gsBool gsString::operator!=( const gsString& other )
{
	return !(*(this) == other);
}
	
gsBool gsString::operator>( const gsString& other )
{
	gsUInt index = 0;
	gsBool result = false;
	
	if( other.m_size > m_size )
	{
		while( index < m_size )
		{
			if( *( m_buffer + index ) > *( other.m_buffer + index ) )
			{
				result = true;
			}
			
			index++;
		}
	}
	else
	{
		while( index < other.m_size )
		{
			if( *( m_buffer + index ) > *( other.m_buffer + index ) )
			{
				result = true;
			}
			
			index++;
		}
	}
	
	return result;
}
	
gsBool gsString::operator>=( const gsString& other )
{
	if( stringCompare( m_buffer, other.m_buffer ) )
	{
		return true;
	}
	else
	{
		return ( *(this) > other );
	}
}
	
gsBool gsString::operator<( const gsString& other )
{
	return !( *(this) > other );
}
	
gsBool gsString::operator<=( const gsString& other )
{
	return !( *(this) >= other );
}
	
gsString& gsString::operator+( const gsString& other )
{
	if( other.m_size > ( m_capacity - m_size ) )
	{
		gsUInt increment = m_size + other.m_size + GS_STRING_NULL_TERMINATOR_BUFFER_LENGTH - m_capacity;
		increaseCapacity( increment );
	}
	
	stringConcatenate( m_buffer, other.m_buffer, m_capacity );

	return (*this);
}
	
gsString& gsString::operator+( const gsChar& other )
{
	if( m_capacity - m_size < 1 + GS_STRING_NULL_TERMINATOR_BUFFER_LENGTH )
	{
		increaseCapacity( 1 );
	}
	
	stringCopy( (m_buffer + m_size), &other, 1 );
	
	return (*this);
}
	
gsString& gsString::operator+( const gsChar* other )
{
	if( m_capacity - m_size < stringSize( other ) )
	{
		gsUInt increment = m_size + stringSize( other ) + GS_STRING_NULL_TERMINATOR_BUFFER_LENGTH - m_capacity;
		increaseCapacity( increment );
	}
	
	stringConcatenate( m_buffer, other, m_capacity );
	
	return (*this);
}
		
gsChar& gsString::operator[]( gsUInt index )
{
	if( index < 0 || index >= m_size )
	{
		gsArrayIndexOutOfBoundsException exception;
		throw( exception );
	}
	
	return m_buffer[ index ];
}
		
gsUInt gsString::getCapacity() const
{
	return m_capacity;
}
	
gsUInt gsString::getSize() const
{
	return m_size;
}
	
void gsString::increaseCapacity( gsUInt increment )
{
	if( m_buffer )
	{
		gsUInt newCapacity = m_capacity + increment;
		gsChar* newBuffer = new gsChar[ newCapacity ];
		stringCopy( newBuffer, m_buffer );
		delete[] m_buffer;
		
		m_buffer = newBuffer;
		m_capacity = newCapacity;
	}
	else
	{
		m_buffer = new gsChar[ increment ];
		m_capacity = increment;
	}
}
	
gsUInt gsString::explode( gsChar delimiter, gsContainer< gsString >& container )
{
	return 0;
}

gsInt gsString::stringSize( const gsChar* string, const gsUInt searchLimit )
{
	gsUInt size = 0;
	
	if( searchLimit == 0 )
	{
		while( *( string + size ) != GS_STRING_NULL_TERMINATOR )
		{
			size++;
		}
	}
	else
	{
		while( *( string + size ) != GS_STRING_NULL_TERMINATOR && size < searchLimit )
		{
			size++;
		}
	}
		
	if( searchLimit != 0 && size == searchLimit )
	{
		return -1;
	}
	else
	{
		return size;
	}
}

gsChar* gsString::stringCopy( gsChar* destination, const gsChar* source, gsUInt copyLimit )
{
	gsUInt index = 0;
	
	if( copyLimit == 0 )
	{
		while( *( source + index ) != GS_STRING_NULL_TERMINATOR )
		{
			*( destination + index ) = *( source + index );	
			index++;
		}
	}
	else
	{
		while( *( source + index ) != GS_STRING_NULL_TERMINATOR && index < copyLimit )
		{
			*( destination + index ) = *( source + index );	
			index++;
		}
	}
	
	*( destination + index ) = GS_STRING_NULL_TERMINATOR;
	
	return destination;
}

gsBool gsString::stringCompare( const gsChar* first, const gsChar* second )
{
	gsUInt index = 0;
	
	gsBool result = true;
	
	if( first == GS_NULL || second == GS_NULL )
	{
		result = first == second;
	}
	else if( stringSize( first ) != stringSize( second ) )
	{
		result = false;
	}
	else
	{
		while( *( first + index ) != GS_NULL )
		{
			if( *( first + index ) != *( second + index ) )
			{
				result = false;
			}
		
			index++;
		}
	}
	
	return result;
}

gsChar* gsString::stringConcatenate( gsChar* first, const gsChar* second, gsUInt firstSize )
{
	gsInt secondSize = stringSize( second, firstSize );
	
	if( secondSize == -1 || secondSize > firstSize )
	{
		gsBufferOverRunException exception;
		throw exception;
	}
	else
	{
		gsInt nullPoint = stringSize( first, firstSize );
		
		if( nullPoint != -1 )
		{
			stringCopy( ( first + nullPoint ), second );
		}
		else
		{
			stringCopy( first, second );
		}
	}
	
	return first;
}

gsString::~gsString()
{
	if( m_buffer )
	{
		delete[] m_buffer;
	}
}


